//
//  QSNetRequestTool.swift
//  TestSwift
//
//  Created by Song on 2018/5/14.
//  Copyright © 2018年 Song. All rights reserved.
//

import UIKit
import Alamofire

/// 返回数据格式类型
enum QSResponseType {
    case Response_Json      // Json格式返回
    case Response_String    // String格式返回
}

/// 成功回调
typealias qs_requestSuccess = ((AnyObject) -> ())
/// 失败回调
typealias qs_requestError = ((AnyObject) -> ())
/// 进度回调 进度比例，完成的大小(KB)，总的大小(KB)
typealias qs_Progress = ((Double, Int64, Int64) -> ())

class QSNetRequestTool: NSObject {
    /// 请求管理者
    var sessionManager: Alamofire.SessionManager!
    
    // 单例
    static var share : QSNetRequestTool {
        struct Static {
            static let instance : QSNetRequestTool = QSNetRequestTool()
        }
        // 配置
        Static.instance.qs_config()
        return Static.instance
    }
    
    /// 配置
    private func qs_config() {
        // 配置项
        let configuration = URLSessionConfiguration.default
        // 超时时间
        configuration.timeoutIntervalForRequest = 10
        
        sessionManager = Alamofire.SessionManager(configuration: configuration)
    }
    
    /// get或post，默认get
    ///
    /// - Parameters:
    ///   - urlString: 请求url字符串
    ///   - methodType: 请求类型
    ///   - paraDict: 参数字典
    ///   - encoding: 参数编码格式，默认 URLEncoding.default
    ///   - headers: 请求头
    ///   - responseType: 数据返回格式，默认Json
    ///   - success: 请求成功回调
    ///   - error: 请求失败回调
    func qs_getRequest(urlString: String, methodType: HTTPMethod = .get, paraDict: Dictionary<String, Any>? = nil, encoding: ParameterEncoding = URLEncoding.default, headers: HTTPHeaders? = nil, responseType: QSResponseType = .Response_Json, success: qs_requestSuccess? = nil, error: qs_requestError? = nil) {
        
        Alamofire.request(urlString, method: methodType, parameters: paraDict, encoding: encoding, headers: headers)
            // 返回Json
            .responseJSON { (response) in
                if responseType != .Response_Json {
                    return
                }
                
                // 处理数据
                self.qs_processResult(response: response, success: success, error: error)
        }
            
            // 返回字符串
            .responseString { (response) in
                if responseType != .Response_String {
                    return
                }
                
                // 处理数据
                self.qs_processResult(response: response, success: success, error: error)
        }
    }
    
    /// 上传文件（图片）
    /// 需要转换为二进制流
    ///
    /// - Parameters:
    ///   - urlString: 请求url字符串
    ///   - methodType: 请求类型
    ///   - fileDatasDict: 要上传的文件数据，以字典的格式传递，key是后台指定的key
    ///   - headers: 请求头
    ///   - responseType: 数据返回格式，默认Json
    ///   - success: 请求成功回调
    ///   - error: 请求失败回调
    ///   - progress: 上传进度回调
    func qs_uploadFiles(urlString: String, methodType: HTTPMethod = .post, fileDatasDict: Dictionary<String, Data>, headers: HTTPHeaders? = nil, responseType: QSResponseType = .Response_Json, success: qs_requestSuccess? = nil, error: qs_requestError? = nil, progress: qs_Progress? = nil) {
        
        Alamofire.upload(multipartFormData: { (multipartFormData) in
            for key in fileDatasDict.keys {
                multipartFormData.append(fileDatasDict[key]!, withName: key)
            }
        }, to: urlString, method: methodType, headers: headers) { (encodingResult) in
            switch encodingResult {
            case .success(let upload, _, _):
                // 上传进度
                upload.uploadProgress(closure: { (progr) in
                    #if DEBUG
                    debugPrint(progr.fractionCompleted, progr.completedUnitCount / 1024, progr.totalUnitCount / 1024)
                    #endif
                    
                    if progress != nil {
                        // progress.fractionCompleted == 1.0时表示上传完成
                        progress!(progr.fractionCompleted, progr.completedUnitCount / 1024, progr.totalUnitCount / 1024)
                    }
                })
                
                upload.responseJSON(completionHandler: { (response) in
                    if responseType != .Response_Json {
                        return
                    }
                    
                    // 处理数据
                    self.qs_processResult(response: response, success: success, error: error)
                })
                
                upload.responseString(completionHandler: { (response) in
                    if responseType != .Response_String {
                        return
                    }
                    
                    // 处理数据
                    self.qs_processResult(response: response, success: success, error: error)
                })
            case .failure(let encodingError):
                #if DEBUG
                debugPrint(encodingError)
                #endif
                
                if error != nil {
                    error!(encodingError as AnyObject)
                }
            }
        }
    }
    
    /// 下载文件（图片）
    ///
    /// - Parameters:
    ///   - urlString: 请求url字符串
    ///   - methodType: 请求类型
    ///   - saveLocation: 文件保存的位置（默认保存到document）
    ///   - filePath: 文件保存的具体路径（"file1/myLogo.png"）
    ///   - paraDict: 参数字典
    ///   - encoding: 参数编码格式，默认 URLEncoding.default
    ///   - headers: 请求头
    ///   - success: 请求成功回调
    ///   - error: 请求失败回调
    ///   - progress: 下载进度回调
    func qs_uploadFile(urlString: String, methodType: HTTPMethod = .get, saveLocation: FileManager.SearchPathDirectory = .documentDirectory, filePath: String? = nil, paraDict: Dictionary<String, Any>? = nil, encoding: ParameterEncoding = URLEncoding.default, headers: HTTPHeaders? = nil, success: qs_requestSuccess? = nil, error: qs_requestError? = nil, progress: qs_Progress? = nil) {
        // 指定下载路径和保存文件名
        let destination: DownloadRequest.DownloadFileDestination = { _, response in
            let documentsURL = FileManager.default.urls(for: saveLocation, in: .userDomainMask)[0]
            let fileURL = documentsURL.appendingPathComponent(filePath ?? response.suggestedFilename!)
            // 两个参数表示如果有同名文件则会覆盖，如果路径中文件夹不存在则会自动创建
            return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
        }
        
        Alamofire.download(urlString, method: methodType, parameters: paraDict, encoding: encoding, headers: headers, to: destination)
            
            .downloadProgress { progr in
                #if DEBUG
                debugPrint(progr.fractionCompleted, progr.completedUnitCount / 1024, progr.totalUnitCount / 1024)
                #endif
                
                if progress != nil {
                    // progress.fractionCompleted == 1.0时表示上传完成
                    progress!(progr.fractionCompleted, progr.completedUnitCount / 1024, progr.totalUnitCount / 1024)
                }
            }
            
            .responseData { response in
                switch response.result.isSuccess {
                case true:
                    if success != nil {
                        success!(response.result.value as AnyObject)
                    }
                case false:
                    #if DEBUG
                    debugPrint(response.result.error ?? "")
                    #endif
                    
                    if error != nil {
                        error!(response.result.error as AnyObject)
                    }
                }
            }
    }
    
    /// 取消请求
    ///
    /// - Parameter requestName: 取消某个请求，nil的话全部请求都取消
    func qs_cancelRequest(requestName: String? = nil) {
        self.sessionManager.session.getAllTasks { (tasks) in
            tasks.forEach({ (task) in
                if let name = requestName {
                    if task.currentRequest?.url?.path == name {
                        task.cancel()
                    }
                } else {
                    task.cancel()
                }
            })
        }
    }
    
    /// 处理请求返回的结果(Json)
    ///
    /// - Parameters:
    ///   - response: 返回数据
    ///   - success: 成功
    ///   - error: 错误
    func qs_processResult(response: DataResponse<Any>, success: qs_requestSuccess?, error: qs_requestError?) {
        #if DEBUG
        debugPrint(response.request ?? "")    // original URL request
        debugPrint(response.response ?? "")   // URL response
        debugPrint(response.data ?? "")       // server data
        debugPrint(response.result)     // result of response serialization
        #endif
        
        switch response.result.isSuccess {
        case true:
            if success != nil {
                success!(response.result.value as AnyObject)
            }
        case false:
            #if DEBUG
            debugPrint(response.result.error ?? "")
            #endif
            
            if error != nil {
                error!(response.result.error as AnyObject)
            }
        }
    }
    
    /// 处理请求返回的结果(String)
    ///
    /// - Parameters:
    ///   - response: 返回数据
    ///   - success: 成功
    ///   - error: 错误
    func qs_processResult(response: DataResponse<String>, success: qs_requestSuccess?, error: qs_requestError?) {
        #if DEBUG
        debugPrint(response.request ?? "")    // original URL request
        debugPrint(response.response ?? "")   // URL response
        debugPrint(response.data ?? "")       // server data
        debugPrint(response.result)     // result of response serialization
        #endif
        
        switch response.result.isSuccess {
        case true:
            if success != nil {
                success!(response.result.value as AnyObject)
            }
        case false:
            #if DEBUG
            debugPrint(response.result.error ?? "")
            #endif
            
            if error != nil {
                error!(response.result.error as AnyObject)
            }
        }
    }
}
